package com.iptv.grape.view;

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;

/**
 * 垂直滚动ListView 焦点不 移动，永远在中间
 *
 * @author 章伟 使用说明：
 *          1. lvChannelList.setMaxItemsInOneScreen(7); 设置当前屏幕需要显示多少项
 *          2.lvChannelList.setItemHeight(92); 设置每一项的高度
 *          3.lvChannelList.setAdapter(adapterChanneList); 设置adpter
 *          4.lvChannelList.setInitFocus(3); 设置焦点初始化的位置
 *          5.lvChannelList.setSelection(); 设置焦点跳转到哪里
 *          6. 设置ListView显示的总长度以及在屏幕中的位置
 *         RelativeLayout.LayoutParams rLayoutParamsChannel = new
 *         RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, 7 * 92);
 *         lvChannelList.setLayoutParams(rLayoutParamsChannel);
 *         rLayoutParamsChannel.addRule(RelativeLayout.CENTER_VERTICAL);
 *         8.布局文件参考： 焦点框在关系布局中间 <RelativeLayout
 *         android:id="@+id/livepay_category_rl"
 *         android:layout_width="@dimen/px100"
 *         android:layout_height="match_parent"
 *         android:background="@drawable/bg_category" android:visibility="gone"
 *         > <ImageView android:id="@+id/livepay_category_view_focus"
 *         android:layout_width="match_parent"
 *         android:layout_height="@dimen/px72"
 *         android:layout_centerVertical="true" android:focusable="false" />
 *
 *         <com.brlfTv.views.ListViewVScroll
 *         android:id="@+id/livepay_category_view"
 *         android:layout_width="match_parent"
 *         android:layout_height="match_parent"
 *         android:layout_centerVertical="true" android:focusable="true" />
 *         </RelativeLayout>
 *
 *
 */
public class ListViewVScroll extends AdapterView<ListAdapter>
{
    // 新添加的所有子视图在当前最当前最后一个子视图后添加的布局模型
    private static final int LAYOUT_MODE_BELOW = 0;
    // 与LAYOUT_MODE_BELOW相反方向添加的布局模型
    private static final int LAYOUT_MODE_ABOVE = 1;

    private IListViewVScroll iListViewVScroll = null;

    // 视图和数据适配
    private ListAdapter mAdapter;
    // 当前显示最后一个Item在Adapter中位置
    private int mLastItemPosition = -1;
    // 当前显示第一个Item在Adapter中位置
    private int mFirstItemPosition;

    /** 定义头的个数，头只用来显示不移动焦点 **/
    private int headCount = 0;

    /** 当前焦点的位置 **/
    private int focusIndex = 0;
    /** 当前每行的行高 **/
    private int itemHeight = 0;
    /** 一个屏幕中最多显示多少条数据 **/
    private int maxItemsInOneScreen = 0;
    private int middlePos = 0;

    // 当前顶部第一个item
    private int mListTop = 0;
    // 当前第一个显示的item与底部第一个item的顶部偏移量
    private int mListTopOffset = 0;
    /** 额外需要减去的高度 **/
    private int extraHeight = 0;

    // ===========================================================
    // Constructors
    // ===========================================================

    public int getExtraHeight()
    {
        return extraHeight;
    }

    public void setExtraHeight(int extraHeight)
    {
        this.extraHeight = extraHeight;
    }

    public int getItemHeight()
    {
        return itemHeight;
    }

    public void setItemHeight(int itemHeight)
    {
        this.itemHeight = itemHeight;

        mListTop = getListviewHeadTop();

    }

    public ListViewVScroll(Context context)
    {
        super(context);
    }

    public ListViewVScroll(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ListViewVScroll(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    public View getSelectedView()
    {

        return mAdapter.getView(focusIndex, null, this);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);

        // 异常处理
        if (mAdapter == null)
        {
            return;
        }

        if (mDataChanged)
        {
            removeAllViewsInLayout();
            mDataChanged = false;
        }

        // System.out.println("mListTop---------------------" + mListTop);
        // 当前ListView没有任何子视图(Item)，所以依次在从上向下填充子视图
        if (getChildCount() == 0)
        {
            mLastItemPosition = -1;
            // add and measure
            fillListDown(mListTop, 0);
        } else
        {
            final int offset = mListTop + mListTopOffset - getChildAt(0).getTop();
            // remove
            fillList(offset);
        }

        // layout，添加测量完后，获取视图摆放位置
        positioinItems();

        // draw， 上面子视图都添加完了，重绘布局把子视图绘制出来吧
        invalidate();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        // TODO onKeyDown

        // System.out.println("onKeyDown-------lastFocus:" + focusIndex);
        if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
        {

            if (focusIndex >= getAdapter().getCount() - 1)
            {
                return super.onKeyDown(keyCode, event);
            }
            setSelection(focusIndex + 1);
            if (iListViewVScroll != null)
            {
                iListViewVScroll.onItemMove(getSelectedView(), focusIndex);
            }
        } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP)
        {
            if (focusIndex <= headCount)
            {
                return super.onKeyDown(keyCode, event);
            }
            setSelection(focusIndex - 1);
            if (iListViewVScroll != null)
            {
                iListViewVScroll.onItemMove(getSelectedView(), focusIndex);
            }
        } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
        {
            if (iListViewVScroll != null)
            {
                iListViewVScroll.onItemClick(getSelectedView(), focusIndex);
            }
        }

        // System.out.println("onKeyDown-------curFocus:" + focusIndex);

        return super.onKeyDown(keyCode, event);
    }

    /**
     * ListView向上或者向下移动后需要向顶部或者底部添加视图
     *
     * @param offset
     */
    private void fillList(final int offset)
    {
        // 最后一个item的下边界值就是当前ListView的下边界值
        final int bottomEdge = getChildAt(getChildCount() - 1).getBottom();
        fillListDown(bottomEdge, offset);

        // 第一个Item的上边界值就是ListVie的上边界值
        final int topEdge = getChildAt(0).getTop();
        fillListUp(topEdge, offset);
    }

    /**
     * 与fillListDown相反方向添加
     *
     * @param topEdge
     *            当前第一个子视图顶部边界值
     * @param offset
     *            显示区域偏移量
     */
    private void fillListUp(int topEdge, int offset)
    {
        while (topEdge + offset > 0 && mFirstItemPosition > 0)
        {
            // 现在添加的视图时当前子视图后面，所以位置+1
            mLastItemPosition--;

            View newTopChild = mAdapter.getView(mFirstItemPosition, null, this);
            addAndMeasureChild(newTopChild, LAYOUT_MODE_ABOVE);
            int childHeight = newTopChild.getMeasuredHeight();
            topEdge -= childHeight;

            // 在顶部添加视图后，更新顶部偏移
            mListTopOffset -= childHeight;
        }
    }

    /**
     * 向当前最后一个子视图下面添加，填充到当前ListView底部无再可填充区域为止
     *
     * @param bottomEdge
     *            当前最后一个子视图底部边界值
     * @param offset
     *            显示区域偏移量
     */
    private void fillListDown(int bottomEdge, int offset)
    {
        while (bottomEdge + offset < getHeight() && mLastItemPosition < mAdapter.getCount() - 1)
        {
            // 现在添加的视图时当前子视图后面，所以位置+1
            mLastItemPosition++;

            // 数据和视图通过Adapter适配，此处从Adapter获取视图。
            // 第二个参数传入复用的View对象，先出入null，之后再添加View对象复用机制
            View newBottomChild = mAdapter.getView(mLastItemPosition, null, this);
            // **具体添加视图处理
            addAndMeasureChild(newBottomChild, LAYOUT_MODE_BELOW);
            // 添加一个子视图(Item)，随之底部边界也发生改变
            bottomEdge += newBottomChild.getMeasuredHeight();
        }
    }

    /**
     * 向当前ListView添加子视图并负责Measure子视图操作
     *
     * @param child
     *            需要添加的ListView子视图(Item)
     * @param layoutMode
     *            在顶部添加上面添加还是在底部下面添加子视图 ， LAYOUT_MODE_ABOVE 或 LAYOUT_MODE_BELOW
     */
    private void addAndMeasureChild(View child, int layoutMode)
    {
        LayoutParams params = child.getLayoutParams();
        if (params == null)
        {
            params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        }

        final int index = layoutMode == LAYOUT_MODE_ABOVE ? 0 : -1;
        addViewInLayout(child, index, params, true);

        final int itemWidth = getWidth();
        child.measure(MeasureSpec.EXACTLY | itemWidth, MeasureSpec.UNSPECIFIED);
    }

    /**
     * 对所有子视图进行layout操作，取得所有子视图正确的位置
     */
    private void positioinItems()
    {
        int top = mListTop + mListTopOffset;

        for (int i = 0; i < getChildCount(); i++)
        {
            final View child = getChildAt(i);

            // 当前视图未虽然添加到ViewGroup但是还未重新进行measure, layout, draw操作
            // 直接通过child.getWidth();获取不到宽度
            final int width = child.getMeasuredWidth();
            final int height = child.getMeasuredHeight();
            final int left = (getWidth() - width) / 2;

            child.layout(left, top, left + width, top + height);
            top += height;
        }
    }

    @Override
    public ListAdapter getAdapter()
    {
        return mAdapter;
    }

    @Override
    public void setAdapter(ListAdapter adapter)
    {

        if (mAdapter != null)
        {
            mAdapter.unregisterDataSetObserver(mDataObserver);
        }
        mAdapter = adapter;
        mAdapter.registerDataSetObserver(mDataObserver);
        reset();

    }

    private boolean mDataChanged = false;

    private DataSetObserver mDataObserver = new DataSetObserver()
    {

        @Override
        public void onChanged()
        {
            synchronized (ListViewVScroll.this)
            {
                mDataChanged = true;
            }
            invalidate();
            requestLayout();

        }

        @Override
        public void onInvalidated()
        {
            // reset();
            // invalidate();
            // requestLayout();
        }

    };

    public int getFocusIndex()
    {
        return focusIndex;
    }

    public void setInitFocus(int focus)
    {
        // if (getAdapter() == null)
        // {
        // AbLogUtil.e(getContext(), "getAdapter is null");
        // return;
        // }
        //
        // if (focus >= getAdapter().getCount())
        // {
        // middlePos = focus / 2;
        // focus = 0;
        // System.err.println("------setInitFocus focus >= getAdapterCount:focus->"
        // + focus + ",count:" + getAdapter().getCount());
        // } else
        // {
        // middlePos = focus;
        // }
        // // System.out.println("setInitFocus---middlePos:" + middlePos +
        // // ",focusIndex:" + focusIndex);
        // this.focusIndex = focus;
        // mListTop = (middlePos - focusIndex) * getItemHeight() +
        // getListviewHeadTop();
        // requestLayout();
        middlePos = focus;
    }

    private synchronized void reset()
    {

        mListTop = getListviewHeadTop();

        removeAllViewsInLayout();

        requestLayout();
    }

    private int getListviewHeadTop()
    {
        if (maxItemsInOneScreen == 0 || getAdapter() == null)
        {
            return 0;
        }

        int headTop = 0;
        if (maxItemsInOneScreen >= getAdapter().getCount())
        {
            headTop = ((maxItemsInOneScreen - getAdapter().getCount()) / 2) * itemHeight;
        }

        return headTop;
    }

    /**
     * 让屏幕滚动到指定的焦点的位置
     */
    @Override
    public void setSelection(int position)
    {

        if (getAdapter() == null)
        {
            return;
        }

        // if (position >= getAdapter().getCount())
        // {
        // position = 0;
        // System.err.println("------setInitFocus focus >= getAdapterCount:focus->"
        // + position + ",count:" + getAdapter().getCount());
        // }

        focusIndex = position;

        mListTop = (middlePos - position) * getItemHeight() - extraHeight;

        //System.out.println("count:" + getAdapter().getCount() + ",mListTop:" + mListTop + ",middle:" + middlePos + ",position:" + position + "ItemHeight:" + getItemHeight());

        requestLayout();
    }

    public void setFocusIndex(int focusIndex)
    {
        this.focusIndex = focusIndex;
    }

    public void setIListViewVScroll(IListViewVScroll vScroll)
    {
        this.iListViewVScroll = vScroll;
    }

    public interface IListViewVScroll
    {
        public void onItemClick(View view, int focus);

        public void onItemMove(View view, int focus);
    }

    public int getMaxItemsInOneScreen()
    {
        return maxItemsInOneScreen;
    }

    public void setMaxItemsInOneScreen(int maxItemsInOneScreen)
    {
        this.maxItemsInOneScreen = maxItemsInOneScreen;
    }

    public int getMiddlePos()
    {
        return middlePos;
    }

    public void setMiddlePos(int middlePos)
    {
        this.middlePos = middlePos;
    }

    public int getHeadCount()
    {
        return headCount;
    }

    public void setHeadCount(int headCount)
    {
        this.headCount = headCount;
    }
}

